home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / support / postmaster.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-18  |  24.0 KB  |  1,074 lines

  1. /*
  2.  * $Header: /private/postgres/src/support/RCS/postmaster.c,v 1.57 1992/08/12 02:47:20 mao Exp $
  3.  *
  4.  *    POSTMASTER
  5.  *
  6.  *    This program acts as a clearing house for requests to the
  7.  *    POSTGRES system.  Frontend programs send a startup message
  8.  *    to the Postmaster and the postmaster uses the info in the
  9.  *    message to setup a backend process.
  10.  *
  11.  * Initialization:
  12.  *    The Postmaster sets up a few shared memory data structures 
  13.  *     for the backends.  It should at the very least initialize the
  14.  *    lock manager.
  15.  *
  16.  * Synchronization:
  17.  *    The Postmaster shares memory with the backends and will have to lock
  18.  *    the shared memory it accesses.  The Postmaster should never block
  19.  *    on messages from clients.
  20.  *    
  21.  * Garbage Collection:
  22.  *    The Postmaster cleans up after backends if they have an emergency
  23.  *    exit and/or core dump.
  24.  *
  25.  * Communication:
  26.  *
  27.  * Security:  
  28.  *    There is none. Not a little bit.
  29.  *
  30.  * NOTES:
  31.  *
  32.  */
  33.  
  34. #include <signal.h>
  35. #include <sys/file.h>
  36. #include <sys/types.h>
  37. #include <sys/stat.h>
  38. #include <sys/time.h>
  39. #include <errno.h>
  40. #include <fcntl.h>
  41. #include <stdio.h>
  42. #include <netdb.h>
  43. #if !sprite
  44. #include <sys/un.h>
  45. #endif /* !sprite */
  46.  
  47. #include "support/master.h"
  48. #include "utils/log.h"
  49. #include "storage/ipci.h"
  50. #include "tmp/pqcomm.h"
  51. #include "catalog/pg_user.h"
  52. #include "support/list.h"
  53.  
  54. /* default permissions for opening files. */
  55. #define OPEN_PERMISSIONS    (0666)
  56.  
  57. List *ListGarbage;    /* holds used list nodes for future use */
  58. short CommPort;
  59. char ShmIdStr[10];
  60. char ShmSizeStr[10];
  61. extern char *GetPGHome();
  62.  
  63.  
  64. #ifdef DBX_VERSION
  65. #define FORK() (0)
  66. #else
  67. #define FORK() fork()
  68. #endif
  69.  
  70. /*
  71.  * Info for garbage collection.  Whenever a process dies, the Postmaster
  72.  * cleans up after it.  Currently, NO information is required for cleanup,
  73.  * but I left this structure around in case that changed.
  74.  */
  75. typedef struct    bkend    {
  76.   int            pid;    /* process id of backend */
  77. } Backend;
  78.  
  79. /* list of active backends.  For garbage collection only now. */
  80. List    *BackendList;
  81.  
  82.  
  83. /* list of ports associated with still open, but incomplete connections */
  84. List    *PortList;
  85.  
  86. /* for elog() messages.  Port to send the message to. */
  87. Port    *SendPort;
  88.  
  89. /*
  90.  * Default startup message parameters.  
  91.  */
  92. StartupPacket DefaultStartup;
  93.  
  94. /*
  95.  * IOList is used to setup file descriptors of backend processes.
  96.  *    Specify here how the descriptor set of the child (backend)
  97.  *    is different from the parent (Postmaster).  I'm not sure
  98.  *    this stuff works all that well.  I don't use any of the 
  99.  *     sys logs.
  100.  *
  101.  * See descriptor reset for some notes.
  102.  */
  103. typedef struct IOList {
  104.   int    fd;
  105.   char  *name;
  106.   int    mode;
  107. } IOList;
  108.  
  109. #define DEFAULT    ""
  110.  
  111. IOList IO_List[] = {
  112.   { 0, DEFAULT, (O_RDONLY) },
  113.   { 1, DEFAULT, (O_WRONLY | O_APPEND | O_CREAT) },
  114.   { 2, DEFAULT, (O_WRONLY | O_APPEND| O_CREAT) },
  115.   { 0, NULL, 0 },
  116. };
  117.  
  118. extern int NBuffers;
  119.  
  120. extern char *optarg;
  121. extern int opterr;
  122. extern int optind;
  123. extern int errno;
  124.  
  125. extern bool    IsPostmaster;
  126.  
  127. short    PostPortName =    DEF_PORT;
  128. short    ActiveBackends = FALSE;
  129. int    NextBackendId = 0x7fffffff;    /* XXX not sure what this does */
  130.  
  131. char *Usage = "postmaster [ -p port ] [ -b backend_pathname ] [ -d [level] ]\n";
  132. /*
  133.  * Default Values
  134.  */
  135. char Username[USER_NAMESIZE];
  136. char Dbname[64];
  137.  
  138. /* 
  139.  * This is set by getpghome().
  140.  */
  141. char *Home = "";
  142.  
  143. int    ServerSock = INVALID_SOCK;  /* stream socket server */
  144.  
  145. /* 
  146.  * Set by the -d option
  147.  */
  148. int    Debug = 0;
  149.  
  150. /*
  151.  * Set by the -o option
  152.  */
  153. char ExtraOptions[ARGV_SIZE] = {0};
  154.  
  155. /*
  156.  * These globals control the behavior of the postmaster in case some
  157.  * backend dumps core.  Normally, it kills all peers of the dead backend
  158.  * and reinitializes shared memory.  By specifying -s or -n, we can have
  159.  * the postmaster stop (rather than kill) peers and not reinitialize
  160.  * shared data structures.
  161.  */
  162. int    Reinit = 1;
  163. int    SendStop = 0;
  164.  
  165. /* 
  166.  * postmaster.c - function prototypes (none of the funcs are public use)
  167.  */
  168. int ServerLoop ARGS((int serverFd ));
  169. int ConnStartup ARGS((Port *port ));
  170. int ConnCreate ARGS((int serverFd , int *newFdP ));
  171. int PortDestroy ARGS((Port *port ));
  172. int pmdie ARGS((void ));
  173. int reaper ARGS((void ));
  174. int CleanupProc ARGS((int pid , int exitstatus ));
  175. int BackendStartup ARGS((Port *port , StartupPacket *packet , IOList *ioList ));
  176. int fixlead ARGS((char *str , char **dstP , int *sizeP ));
  177. int DoExec ARGS((char *execFile , char *database , int portFd , StartupPacket *pack ));
  178. int DescriptorReset ARGS((IOList *ioList ));
  179. int ExitPostmaster ARGS((int status ));
  180. int FindBackend ARGS((char *backend ));
  181. int ValidBackend ARGS((char *path ));
  182. int ReadObjDir ARGS((char *dir ));
  183. char *zalloc ARGS((unsigned long size ));
  184. #if 0
  185. int *CacheAlloc ARGS((unsigned int size ));
  186. #endif
  187.  
  188. main(argc, argv)
  189. int    argc;
  190. char    *argv[];
  191. {
  192.   char      *getenv();
  193.   char        getopt();
  194.   char        opt;
  195.   int        serverMask;
  196.   char        *hostName;
  197.   int        status;
  198.   int        size;
  199.   char         sysLogPath[PATH_SIZE];
  200.   char        *sysLogPtr = sysLogPath;
  201.   char         dblogPath[PATH_SIZE];
  202.   char        *dblogPtr = dblogPath;
  203.  
  204.   /*
  205.    * Initialize signal handlers.  I took this from Dillon's code.
  206.    * Not sure who made the decision about what signals to handle.
  207.    */
  208.   signal(SIGCHLD, reaper);
  209.   signal(SIGTTIN, SIG_IGN);
  210.   signal(SIGTTOU, SIG_IGN);
  211.   
  212.   signal(SIGHUP, pmdie);
  213.   signal(SIGINT, pmdie);
  214.   signal(SIGTERM, pmdie);
  215.  
  216.   ListHead(&ListGarbage);    /* initialize ListGarbage */
  217.  
  218.   if (!(hostName = getenv("PGHOST"))) {
  219.     hostName = "localhost";
  220.   }
  221.  
  222.   opterr = 0;
  223.   while ((opt = getopt(argc, argv, "B:b:dno:p:s")) != EOF) {
  224.     switch (opt) {
  225.         case 'B':
  226.             /*
  227.              * The number of buffers to create.  Setting this
  228.              * option means we have to start each backend with
  229.              * a -B # to make sure they know how many buffers
  230.              * were allocated.
  231.              */
  232.             NBuffers = atol(optarg);
  233.             strcat(ExtraOptions, "-B ");
  234.             strcat(ExtraOptions, optarg);
  235.             break;
  236.         case 'b':
  237.             if (ValidBackend(optarg))
  238.                   strcpy(DefaultStartup.execFile, optarg);
  239.             else
  240.                 fprintf(stderr, "%s %s",
  241.                       "Couldn't find the requested backend",
  242.                       "-- Using a default search path...\n");
  243.             break;
  244.         case 'd':
  245.             if ((optind < argc) && *argv[optind] != '-') {
  246.                 Debug = atoi(argv[optind]);
  247.                 optind++;
  248.             }
  249.             else
  250.                 Debug = 1;
  251.             break;
  252.         case 'n':
  253.             /* don't reinit shared mem after abnormal exit */
  254.             Reinit = 0;
  255.             break;
  256.         case 'o':
  257.             /*
  258.              * Other options to pass to the backend on the
  259.              * command line -- Useful only for debugging.
  260.              */
  261.             strcat(ExtraOptions, optarg);
  262.             break;
  263.         case 'p':
  264.             PostPortName = (short)atoi(optarg);
  265.             break;
  266.         case 's':
  267.             /*
  268.              *  In the event that some backend dumps core,
  269.              *  send SIGSTOP, rather than SIGUSR1, to all
  270.              *  its peers.  This lets the wily post_hacker
  271.              *  collect core dumps from everyone.
  272.              */
  273.             SendStop = 1;
  274.             break;
  275.         default:
  276.             perror("argument list");
  277.             fprintf(stderr, "Usage: %s", Usage);
  278.             exit(errno);
  279.             break;
  280.     }
  281.   }
  282.  
  283.   IsPostmaster = true;
  284.  
  285.   Home = GetPGHome();
  286.  
  287.   /* default startup values */
  288.   if (! DefaultStartup.execFile[0])
  289.       FindBackend(DefaultStartup.execFile);
  290.  
  291.   strncpy(Username, getenv("USER"), USER_NAMESIZE);
  292.   strcpy(DefaultStartup.user, Username);
  293.   strcpy(DefaultStartup.database,Username);
  294.   strcpy(Dbname, Username);
  295.  
  296.   status = StreamServerPort(hostName,PostPortName, &ServerSock);
  297.   if (status != STATUS_OK)  {
  298.     elog(WARN,"PostMaster:cannot create stream port") ;
  299.     exit(1);
  300.   }
  301.  
  302.   /* set up shared memory and semaphores */
  303.   EnableMemoryContext(TRUE);
  304.   CreateSharedMemoryAndSemaphores(
  305.     SystemPortAddressCreateIPCKey((SystemPortAddress)PostPortName));
  306.  
  307.   /*
  308.    * Initialize the list of active backends.  This list is only
  309.    * used for garbage collecting the backend processes.
  310.    */
  311.   ListHead(&BackendList);
  312.   ListHead(&PortList);
  313.  
  314.   status = ServerLoop(ServerSock);
  315.   ExitPostmaster(status != STATUS_OK);
  316. }
  317.  
  318. ServerLoop(serverFd)
  319. int    serverFd;
  320. {
  321.   int        mask;
  322.   int        baseMask;
  323.   int        serverMask;
  324.   int        nSockets;
  325.   int        nSelected;
  326.   int        status;
  327.   int        dummy;
  328.   List        *curr;
  329.  
  330.   nSockets  = ServerSock+1;
  331.   baseMask = 1 << ServerSock;
  332.   serverMask = baseMask;
  333.  
  334.   for (;;) {
  335.     dummy = 0;
  336.     mask = baseMask;
  337.     if ((nSelected = select(nSockets, &mask, &dummy, &dummy, NULL)) < 0) {
  338.       if (errno == EINTR)
  339.     continue;
  340.       elog(WARN,"Postmaster: select failed");
  341.       return(STATUS_ERROR);
  342.     }
  343.  
  344.     if (serverMask & mask) {
  345.       int    newFd;
  346.       int    newMask;
  347.  
  348.       status = ConnCreate(serverFd, &newFd);
  349.  
  350.       if (newFd >= nSockets)
  351.     nSockets = newFd+1;
  352.  
  353.       /* read the new connection on the first pass */
  354.       newMask = 1 << newFd;
  355.       nSelected--;
  356.       /* add the new connection to the baseMask */
  357.       baseMask |= newMask;
  358.     }
  359.  
  360.     ListForEach( curr, PortList, PortList) {
  361.       ConnId        connId;    /* dummy argument */
  362.       Port        *port;    /* port for I/O */
  363.  
  364.       port = (Port *) ListElem(curr);
  365.  
  366.       if (port->mask & mask) {
  367.     nSelected--;
  368.     
  369.     /*
  370.      * read the incoming packet into its packet buffer.  Read the
  371.      * connection id out of the packet so we know who the packet
  372.      * is from. 
  373.      */
  374.     status = PacketReceive(port, (Addr) &port->buf,
  375.                    NON_BLOCKING, &connId);
  376.     switch (status) {
  377.     case STATUS_OK:
  378.       ConnStartup (port);
  379.       ActiveBackends = TRUE;
  380.       baseMask &= ~ port->mask;
  381.       PortDestroy (port) ;
  382.       ListDelete (curr) ;
  383.       break;
  384.  
  385.     case STATUS_INVALID:
  386.       baseMask &= ~ port->mask;
  387.       PortDestroy (port) ;
  388.       ListDelete (curr) ;
  389.       break;
  390.  
  391.     case STATUS_NOT_DONE:
  392.       break;
  393.  
  394.     case STATUS_ERROR:
  395.       elog(WARN,"Postmaster: error receiving packet\n");
  396.       return(STATUS_ERROR);
  397.     }
  398.       }
  399.     }
  400.     Assert (! nSelected);
  401.   }
  402.   /* shouldn't ever get here */
  403. }
  404.  
  405. ConnStartup(port)
  406. Port    *port;        /* receiving port */    
  407. {
  408.     int     status;        /* procedure return code */
  409.     MsgType    msgType;    /* type of message recieved */
  410.     SeqNo    seqno= INITIAL_SEQNO;/* dummy argument expected by packetData*/
  411.     PacketLen    bufSize;    /* dummy argument */
  412.     Addr    buf;        /* dummy argument */
  413.  
  414.     /*
  415.      * Get the packet header information.
  416.      */
  417.     PacketData((Addr) &port->buf, &buf, &bufSize, &msgType,  &seqno);
  418.     if (msgType != STARTUP_MSG) {
  419.       elog(WARN,"Postmaster: unrecognized message type\n");
  420.       return(STATUS_ERROR);
  421.     }
  422.     if (BackendStartup(port, (StartupPacket *)&port->buf, IO_List) != STATUS_OK)
  423.     {
  424.       elog(WARN,"Postmaster: couldn't startup backend for client\n");
  425.       return(STATUS_ERROR);
  426.     }
  427.     return(STATUS_OK);
  428. }
  429.  
  430.  
  431. /*
  432.  * ConnCreate -- create a local connection data structure
  433.  */
  434. ConnCreate(serverFd, newFdP)
  435. int        serverFd;
  436. int        *newFdP;
  437. {
  438.   Connection    *conn;
  439.   int        connId;
  440.   int        status;
  441.   long        currTime;
  442.   int        newFd;
  443.   Port        *port = (Port *) zalloc(sizeof(Port));
  444.  
  445.  
  446.   status = StreamConnection(serverFd,&newFd,&port->addr);
  447.  
  448.   port->sock = newFd;
  449.   port->mask = 1 << newFd;
  450.  
  451.   ListPush(PortList, port);
  452.   *newFdP = newFd;
  453.  
  454.   /* in case of error message */
  455.   SendPort = port;
  456.  
  457.   /* 
  458.    * If there was an error in the port creation, the connection
  459.    * struct should be freed again.
  460.    */
  461.   if (status != STATUS_OK) {
  462.     PortDestroy ( port ) ;
  463.   }
  464.  
  465.   return(status);
  466. }
  467.  
  468. PortDestroy(port)
  469. Port    *port;
  470. {
  471.   StreamClose( port->sock );
  472.   free ((char *)port);
  473. }
  474.  
  475. /*
  476.  * pmdie -- signal handler for cleaning up after a kill signal.
  477.  */
  478. pmdie()
  479. {
  480.   exitpg(0);
  481. }
  482.  
  483. /*
  484.  * Reaper -- signal handler to cleanup after a backend (child) dies.
  485.  *
  486.  */
  487. reaper()
  488. {
  489. #ifdef linux
  490.   int        status;
  491. #else
  492.   union    wait    status;        /* backend exit status */
  493. #endif
  494.   struct    rusage    ruse;    /* resource usage structure */
  495.   int        pid;        /* process id of dead backend */
  496.  
  497.   if (Debug)
  498.     fprintf(stderr, "In reaper\n");
  499.   while ((pid = wait3(&status, WNOHANG, &ruse)) > 0) {
  500. #ifdef linux
  501.     (void) CleanupProc(pid,WEXITSTATUS(status));
  502. #else
  503.     (void) CleanupProc(pid,status.w_status);
  504. #endif
  505.   }
  506. }
  507.  
  508. /*
  509.  * CleanupProc -- cleanup after terminated backend.
  510.  *
  511.  * Remove all local state associated with backend.
  512.  *
  513.  * Dillon's note: should log child's exit status in the system log.
  514.  */
  515. CleanupProc(pid,exitstatus)
  516. int    pid;
  517. int    exitstatus;        /* child's exit status. */
  518. {
  519.   List    *curr;
  520.   int sig;
  521.  
  522.   if (Debug)
  523.   {
  524.     fprintf(stderr, "In CleanUpProc - ");
  525.     fprintf(stderr, "Backend with pid %d exited with status %d\n", pid, exitstatus);
  526.     fflush(stderr);
  527.   }
  528.   /* -------------------------
  529.    * If a backend dies in an ugly way (i.e. status not 0) then
  530.    * we must signal all other backends to quickdie.  If exit status
  531.    * is zero we assume everything is hunky dory and simply remove the
  532.    * backend from the active backend list.
  533.    * -------------------------
  534.    */
  535.   if (!exitstatus)
  536.   {
  537.       ListForEach( curr, BackendList, BackendList)
  538.       {
  539.         Backend *bp = (Backend *) ListElem(curr);
  540.  
  541.     if (bp->pid == pid)
  542.     {
  543.       (void) free ((char *)bp);
  544.       ListDelete(curr);
  545.       break;
  546.     }
  547.       }
  548.       return(STATUS_OK);
  549.   }
  550.   ListForEach( curr, BackendList, BackendList)
  551.   {
  552.     Backend *bp = (Backend *) ListElem(curr);
  553.       
  554.     /* -----------------
  555.      * SIGUSR1 is the special signal that sez exit without exitpg
  556.      * and let the user know what's going on.  ProcSemaphoreKill() 
  557.      * cleans up the backends semaphore.  If SendStop is set (-s on
  558.      * the command line), then we send a SIGSTOP so that we can collect
  559.      * core dumps from all backends by hand.
  560.      * -----------------
  561.      */
  562.     if (SendStop)
  563.     sig = SIGSTOP;
  564.     else
  565.     sig = SIGUSR1;
  566.     if (bp->pid != pid)
  567.     {
  568.     if (Debug)
  569.       fprintf(stderr, "Sending %s to process %d\n",
  570.           (sig == SIGUSR1 ? "SIGUSR1" : "SIGSTOP"), bp->pid);
  571.     kill(bp->pid, sig);
  572.     ProcSemaphoreKill(bp->pid);
  573.     }
  574.     else
  575.     ProcSemaphoreKill(bp->pid);
  576.  
  577.     (void) free ((char *)bp);
  578.     ListDelete(curr);
  579.   }
  580.   /* -------------
  581.    * Quasi_exit means run all of the on_exitpg routines but don't
  582.    * acutally call exit().  The on_exit list of routines to do is
  583.    * also truncated.
  584.    *
  585.    * Nothing up my sleeve here, ActiveBackends means that since the last time
  586.    * we recreated shared memory and sems another frontend has requested and
  587.    * received a connection and I have forked off another backend.  This
  588.    * prevents me from reinitializing shared stuff more than once for the
  589.    * set of backends that caused the failure and were killed off.
  590.    * ----------------
  591.    */
  592.   if (ActiveBackends == TRUE && Reinit)
  593.   {
  594.     if (Debug)
  595.       fprintf(stderr, "Reinitializing shared memory and semaphores\n");
  596.     quasi_exitpg();
  597.     /* --------------
  598.      * Recreate shared memory and semaphores.
  599.      * --------------
  600.      */
  601.     CreateSharedMemoryAndSemaphores(
  602.       SystemPortAddressCreateIPCKey((SystemPortAddress)PostPortName));
  603.     ActiveBackends = FALSE;
  604.   }
  605.     return(STATUS_OK);
  606. }
  607.  
  608. /*
  609.  * BackendStartup -- startup backend process
  610.  *
  611.  * returns: STATUS_ERROR if the fork/exec failed, STATUS_OK
  612.  *    otherwise.
  613.  *
  614.  */
  615. BackendStartup(port, packet, ioList)
  616. Port        *port;
  617. StartupPacket    *packet;   /* client's startup packet */
  618. IOList        *ioList;   /* io devices to setup */
  619. {
  620.   int        status;       /* return status */
  621.   Backend     *bp;       /* info to be used for backend cleanup */
  622.   char        dbData[PATH_SIZE];
  623.   char        efData[ARGV_SIZE];
  624.   char        *execFile;
  625.   char        *database;  /* database after fixlead */
  626.   int        size;       /* of fixlead string */
  627.   int        pid;
  628.  
  629.   database = dbData;
  630.   execFile = efData;
  631.  
  632.   bp = (Backend *) zalloc(sizeof(Backend));
  633.   if (! bp) {
  634.     elog(FATAL,"Postmaster: cannot zalloc backend structure\n");
  635.     ExitPostmaster(1);
  636.   }
  637.   ListPush(BackendList,bp);
  638.  
  639.   /*
  640.    * If any of the arguments is missing, use the defaults.
  641.    */
  642.  
  643.   /* Set up the backend as specified by the startup packet */
  644.  
  645.   if (* (packet->tty)) {    /* Stdout/Stderr will become the tty file */
  646.     ioList[1].name = packet->tty;
  647.     ioList[2].name = packet->tty;
  648.   }
  649.  
  650.   if (! * (packet->user)) 
  651.     strcpy(packet->user,DefaultStartup.user);
  652.  
  653.   size = PATH_SIZE;
  654.   if (! * (packet->database)) 
  655.     strcpy(database,DefaultStartup.database);
  656.   else 
  657.     (void) fixlead(packet->database,&database,&size);
  658.  
  659.   database = dbData;
  660.     
  661.   size = ARGV_SIZE;
  662.   if (! * (packet->execFile))
  663.     strcpy(execFile, DefaultStartup.execFile);
  664.   else
  665.     (void) fixlead(packet->execFile, &execFile, &size);
  666.  
  667.   execFile = efData;
  668.  
  669.   /*
  670.    * Security: check the arguments.  There should be an authorized
  671.    *    list of execFiles at the very least.
  672.    */
  673.  
  674.   if ((pid = FORK()) == 0) {
  675.     /* child: 
  676.      *     use the ioList structure to setup your file descriptors and
  677.      *     then exec the file requested.
  678.      */
  679.     /*
  680.      * These have to be made big enough!
  681.      */
  682.     char    envEntry1[64];
  683.     char    envEntry2[64];
  684.     char    envEntry3[64];
  685.  
  686.     /* This goes to backend as command line arg!!!
  687.      * dup2(port->sock,BACKEND_SOCK); 
  688.      */
  689.     status = DescriptorReset(ioList);
  690.     if (status) {
  691.       _exit(1);
  692.     }
  693.  
  694.     /* Set up the necessary environment variables for the backend
  695.      * This should really be some sort of message....
  696.      */
  697. #ifdef sprite
  698.     { 
  699.       char c[50];
  700.       sprintf(c, "%d", PostPortName);
  701.       setenv("POSTPORT", c);
  702.       sprintf(c, "%d", NextBackendId);
  703.       setenv("POSTID", c);
  704.       sprintf(c, "%s", packet->user);
  705.       setenv("PG_USER", c);
  706.     }
  707. #else
  708.  
  709.     sprintf(envEntry1, "POSTPORT=%d", PostPortName);
  710.     putenv(envEntry1);
  711.     sprintf(envEntry2, "POSTID=%d", NextBackendId);
  712.     putenv(envEntry2);
  713.     sprintf(envEntry3, "PG_USER=%s", packet->user);
  714.     putenv(envEntry3);
  715.     if (Debug) {
  716.     printf("ENVIRONMENT: %s, %s, %s\n", envEntry1,envEntry2,envEntry3);
  717.     }
  718.  
  719. #endif /* sprite */
  720.  
  721.     if (! DoExec(execFile, database, port->sock,packet)) {
  722.       return;
  723.     }
  724.  
  725.     /* error -- exec has failed if we get here. */
  726.     elog(FATAL,"Postmaster: DoExec failed for '%s'\n",DefaultStartup.execFile);
  727.     _exit(1);
  728.   }
  729.  
  730.   if (Debug)
  731.     fprintf(stderr,
  732.         "started '%s' for '%s' on '%s' (%d) pid (%d)\n",
  733.          execFile,packet->user, database,port->sock, pid);
  734.  
  735.   if (pid < 0) {
  736.     fprintf(stderr, "PostMaster: fork failed");
  737.     return(STATUS_ERROR);
  738.   } 
  739.   else
  740.     bp->pid = pid;
  741.  
  742.   /* adjust backend counter */
  743.   /* XXX Don't know why this is done, but for now backend needs it */
  744.   NextBackendId -= 1;
  745.  
  746.   return(STATUS_OK);
  747. }
  748.  
  749. /* 
  750.  * fixlead -- Expand special characters from path names. 
  751.  * 
  752.  * returns: TRUE if expansion occurred FALSE otherwise.
  753.  * SIDE EFFECTS: copies str into dst
  754.  *
  755.  * NOTES: this does not use the sizeP parameter.  It should
  756.  *    check for string overflow.
  757.  */
  758. fixlead(str, dstP, sizeP)
  759. char    **dstP, *str;
  760. int    *sizeP;
  761. {
  762.   char *dst = *dstP;
  763.   int    size = *sizeP;
  764.   int    status = TRUE;
  765.  
  766.   switch (*str) {
  767.     /* carriage return == NULL */
  768.   case '\n':
  769.     return(FALSE);
  770.  
  771.   case '~':
  772.  
  773.     /* home directory of postgres installation */
  774.     strcpy(dst, Home);
  775.     break;
  776.  
  777.   case '&':
  778.     strcpy(dst, Home);
  779.     strcat(dst, "/data/base/");
  780.     strcat(dst, Dbname);
  781.     break;
  782.  
  783.     /* directory of database */
  784.   case '%':
  785.     strcpy(dst, Home);
  786.     strcat(dst, "/data");
  787.     break;
  788.     /* directory of global data (should be '&/..') */
  789.   default:
  790.     *dst = '\0';
  791.     status = FALSE;
  792.   }
  793.   if (status)
  794.     str++;
  795.  
  796.   strncat(dst,str,size);
  797.   size = strlen(dst);
  798.   *dstP += size;
  799.   *sizeP -= size;
  800.   return(status);
  801. }
  802.  
  803.  
  804. /*
  805.  * DoExec -- setup the arguments and make an execv system call.
  806.  *
  807.  * returns: 
  808.  *    if not debugging, we shouldn't return at all (exec()).
  809.  *    if debugging, return 0.
  810.  *    if exec fails, return 1.
  811.  */
  812. DoExec(execFile,database, portFd, pack)
  813. char    *execFile,*database;
  814. StartupPacket    *pack;
  815. int     portFd;
  816. {
  817.   int    status;
  818.   char portBuf[32];
  819.   char debugBuf[32];
  820.   char startDir[PATH_SIZE];
  821.   char args[2*ARGV_SIZE];
  822.   
  823.   /*
  824.    * Call backend with any/all desired options.  These extra options
  825.    * can either come from the front-end via the packet or from the
  826.    * command line of the postmaster -o option.
  827.    */
  828.   args[0] = '\0';
  829.   if (pack->options[0])
  830.       strcpy(args, pack->options);
  831.   if (ExtraOptions[0])
  832.     strcat(args, ExtraOptions);
  833.  
  834.   status = 1;
  835.  
  836.   strcpy(startDir, Home);
  837.   strcat(startDir, "/data/base/");
  838.   strcat(startDir, pack->database);
  839.   if (chdir(startDir))
  840.     perror(startDir);
  841.   /* If debugging requested pass the request along to the backend */
  842.   if (Debug)
  843.     sprintf(debugBuf, "-d %d", Debug);    
  844.   else
  845.     sprintf(debugBuf, "-Q");
  846.  
  847.   sprintf(portBuf, "-P%d", portFd);
  848.   if (Debug) {
  849.     printf("The port file descriptor is %d\n", portFd);
  850.     printf("execl: %s -p %s %s %s %s\n", 
  851.         execFile, debugBuf, portBuf, database, args);
  852.   }
  853.   if (!(*args)) {
  854.   status =
  855.     execl(execFile, execFile, "-p", debugBuf, portBuf, database, NULL);
  856.   }
  857.   else {
  858.     status =
  859.       execl(execFile, execFile, "-p", debugBuf, portBuf, args, database, NULL);
  860.   }
  861.   return(status);
  862. }
  863.  
  864.  
  865. /*
  866.  * DescriptorReset -- reset the servers file descriptors to
  867.  *    match the configuration the new backend expects.
  868.  *
  869.  * This routine closes, stdin etc.  It'll set up a log file.
  870.  */
  871. DescriptorReset(ioList)
  872. IOList    *ioList;
  873. {
  874.   /*
  875.    * For each element of the io list: 
  876.    *   If the name is NONE, close the corresponding file descriptor.
  877.    *   If the name is DEFAULT, let the child inherit the parent's descriptors.
  878.    *   Otherwise, open the named descriptor.
  879.    */
  880.   for (;ioList->name;ioList++) {
  881.     if (! strcmp(ioList->name, "NONE")) {
  882.       close(ioList->fd);
  883.     } else if (strcmp(ioList->name,DEFAULT)) {
  884.       int tmpfd;
  885.  
  886.       if (! (tmpfd = open(ioList->name, ioList->mode, OPEN_PERMISSIONS))) {
  887.     perror(ioList->name);
  888.     fprintf(stderr,"PostMaster: child cannot open tty '%s'\n",ioList->name);
  889.     return(STATUS_ERROR);
  890.       }
  891.       close(ioList->fd);
  892.       dup2(tmpfd,ioList->fd);
  893.       close(tmpfd);
  894.     }
  895.   }
  896.   return(STATUS_OK);
  897. }
  898.  
  899. /*
  900.  * ExitPostmaster -- cleanup
  901.  */
  902. ExitPostmaster(status)
  903. {
  904.   /* should cleanup shared memory and kill all backends */
  905.  
  906.   /*
  907.    * Not sure of the semantics here.  When the Postmaster dies,
  908.    * should the backends all be killed? probably not.
  909.    */
  910.   if (ServerSock != INVALID_SOCK)
  911.     close(ServerSock);
  912.   exitpg(status);
  913. }
  914.  
  915. /* Delete this once the simple list implementation is ready */
  916.  
  917. #define MAX_SIZE 450000
  918. #define MALLOC_MAGICNO        'M'
  919. #define PRINT_ALLOC(STR, STR1, NUM)
  920. #define DO_ALLOC(size)
  921. #define TOP_ADDR(str)
  922. int TotalCacheAlloc;
  923.  
  924. int *
  925. CacheAlloc(size)
  926. unsigned int size;
  927. {
  928.   char *tmp;
  929.  
  930.   Assert(size);
  931.   Assert(size < MAX_SIZE);
  932.   /* have to add four bytes because zalloc is going to align the space */
  933.   tmp = (char *)zalloc(size+4);
  934.   Assert(tmp);
  935.   TOP_ADDR(tmp);
  936.   PRINT_ALLOC("CacheAlloc",tmp,size);
  937.   DO_ALLOC(TotalCacheAlloc += size);
  938.  
  939.   *(tmp+3) = MALLOC_MAGICNO;
  940.   tmp += 4;
  941.  
  942.   return((int *)tmp);
  943. }
  944.  
  945. FindBackend(backend)
  946. char *backend;
  947. {
  948.     char path[PATH_SIZE];
  949.     char objDir[PATH_SIZE];
  950.     char *envVar;
  951.     struct stat buf;
  952.  
  953.     /* check $POSTGRESHOME/bin/postgres */
  954.  
  955.     envVar = getenv("POSTGRESHOME");
  956.     if (envVar) {
  957.         strncpy(path, envVar, PATH_SIZE-21);
  958.         strcat(path, "/bin/postgres");
  959.         if (ValidBackend(path)) {
  960.             strcpy(backend, path);
  961.             return;
  962.         }
  963.     }
  964.  
  965.     /* check $POSTTREE/bin/postgres */
  966.  
  967.     envVar = getenv("POSTTREE");
  968.     if (envVar) {
  969.         strncpy(path, envVar, PATH_SIZE-21);
  970.         strcat(path, "/bin/postgres");
  971.         if (ValidBackend(path)) {
  972.             strcpy(backend, path);
  973.             return;
  974.         }
  975.     }
  976.  
  977.     /* check $POSTTREE/<obj.dir>/support/postgres */
  978.  
  979.     ReadObjDir(objDir);
  980.  
  981.     if (objDir[0]) {
  982.         strncpy(path, objDir, PATH_SIZE-21);
  983.         strcat(path, "/support/postgres");
  984.         if (ValidBackend(path)) {
  985.             strcpy(backend, path);
  986.             return;
  987.         }
  988.     }
  989.  
  990.     /* check /usr/postgres/bin/postgres */
  991.  
  992.     strncpy(path, "/usr/postgres/bin/postgres", PATH_SIZE);
  993.     if (ValidBackend(path)) {
  994.         strcpy(backend, path);
  995.         return;
  996.     }
  997.     fprintf(stderr,"Could not find a backend to execute -- giving up...\n");
  998.     fprintf(stderr,"Have you set POSTGRESHOME in your environment?\n");
  999.     fprintf(stderr,"Have you installed everything successfully?\n");
  1000.     exit(1);
  1001. }
  1002.  
  1003. ValidBackend(path)
  1004. char *path;
  1005. {
  1006.     struct stat buf;
  1007.  
  1008.     if ( stat(path, &buf) < 0 )
  1009.         return (FALSE);
  1010.     else if ( ! (buf.st_mode & S_IEXEC) )
  1011.         return (FALSE);
  1012.     else
  1013.         return (TRUE);
  1014. }
  1015.  
  1016. ReadObjDir(dir)
  1017. char *dir;
  1018. {
  1019.     FILE *fp;
  1020.     char buf[256];
  1021.     char tmpFile[32];
  1022.     char *bufptr;
  1023.     char *envPtr;
  1024.  
  1025.     /* Look for $POSTTREE/newconf/config.mk */
  1026.  
  1027.     if ((envPtr = getenv("POSTTREE")) == NULL)
  1028.     {
  1029.         *dir = '\0';
  1030.         return;
  1031.     }
  1032.  
  1033.     /* make a temporary file */
  1034.     sprintf(tmpFile, "/tmp/pm.%d", getpid());
  1035.  
  1036.     sprintf(buf, 
  1037.         "fgrep OD= %s/newconf/config.mk | sed -e \'s/OD=\t//\' > %s",
  1038.         envPtr,
  1039.         tmpFile);
  1040.  
  1041.     system( buf );
  1042.  
  1043.     if ((fp = fopen(tmpFile, "r")) == NULL) {
  1044.         *dir = '\0';
  1045.         return;
  1046.     }
  1047.  
  1048.     fgets(buf, 255, fp);
  1049.  
  1050.     /* kill the annoying \n fgets always puts at the end of the line */
  1051.  
  1052.     bufptr = (char *)index(buf, '\n');
  1053.     if (bufptr)
  1054.         *bufptr = (char)NULL;
  1055.     strncpy(dir, buf, PATH_SIZE);
  1056.  
  1057.     fclose(fp);
  1058.     unlink(tmpFile);
  1059.     return;
  1060. }
  1061.  
  1062. char *
  1063. zalloc(size)
  1064.  
  1065. unsigned long size;
  1066.  
  1067. {
  1068.     char *t;
  1069.  
  1070.     t = (char *) malloc(size);
  1071.     bzero(t, size);
  1072.     return(t);
  1073. }
  1074.